#pragma once

#include "ExceptionHandler.h"

#include "Classifier.h"
#include "ExecutableNode.h"
#include "ObjectNode.h"

namespace uml {

ExceptionHandler::ExceptionHandler(const QString& umlType)
    : Element(umlType) {}

void ExceptionHandler::fromJson(const QJsonObject& json, QStringList& errorList) {
    if (json.isEmpty()) {
        return;
    }

    Element::fromJson(json, errorList);
    exceptionInput_ = JsonSerializable::create<ObjectNode>(json.value("exceptionInput"), errorList);

    JsonSerializable::fromJsonArray(exceptionTypes_, "exceptionTypes", json, errorList);
    handlerBody_ = JsonSerializable::create<ExecutableNode>(json.value("handlerBody"), errorList);

    protectedNode_ = JsonSerializable::create<ExecutableNode>(json.value("protectedNode"), errorList);

}

void ExceptionHandler::toJson(QJsonObject& json) {
    Element::toJson(json);
    if (exceptionInput_) {
        QJsonObject exceptionInput_json;
        exceptionInput_->toJson(exceptionInput_json);
        json.insert("exceptionInput", exceptionInput_json);
    }
    JsonSerializable::toJsonArray(exceptionTypes_, "exceptionTypes", json);
    if (handlerBody_) {
        QJsonObject handlerBody_json;
        handlerBody_->toJson(handlerBody_json);
        json.insert("handlerBody", handlerBody_json);
    }
    if (protectedNode_) {
        QJsonObject protectedNode_json;
        protectedNode_->toJson(protectedNode_json);
        json.insert("protectedNode", protectedNode_json);
    }
}

/// <summary>
/// exceptionInput getter
/// An ObjectNode within the handlerBody. When the ExceptionHandler catches an
/// exception, the exception token is placed on this ObjectNode, causing the
/// handlerBody to execute.
/// </summary>
shared_ptr<ObjectNode> ExceptionHandler::exceptionInput() const {
    return exceptionInput_;
}

/// <summary>
/// exceptionInput setter
/// An ObjectNode within the handlerBody. When the ExceptionHandler catches an
/// exception, the exception token is placed on this ObjectNode, causing the
/// handlerBody to execute.
/// </summary>
void ExceptionHandler::setExceptionInput(shared_ptr<ObjectNode> value) {
    exceptionInput_ = value;
}

/// <summary>
/// exceptionTypes getter
/// The Classifiers whose instances the ExceptionHandler catches as exceptions. If
/// an exception occurs whose type is any exceptionType, the ExceptionHandler
/// catches the exception and executes the handlerBody.
/// </summary>
vector<shared_ptr<Classifier>>& ExceptionHandler::exceptionTypes() {
    return exceptionTypes_;
}

/// <summary>
/// handlerBody getter
/// An ExecutableNode that is executed if the ExceptionHandler catches an exception.
/// </summary>
shared_ptr<ExecutableNode> ExceptionHandler::handlerBody() const {
    return handlerBody_;
}

/// <summary>
/// handlerBody setter
/// An ExecutableNode that is executed if the ExceptionHandler catches an exception.
/// </summary>
void ExceptionHandler::setHandlerBody(shared_ptr<ExecutableNode> value) {
    handlerBody_ = value;
}

/// <summary>
/// protectedNode getter
/// The ExecutableNode protected by the ExceptionHandler. If an exception propagates
/// out of the protectedNode and has a type matching one of the exceptionTypes, then
/// it is caught by this ExceptionHandler.
/// </summary>
shared_ptr<ExecutableNode> ExceptionHandler::protectedNode() const {
    return protectedNode_;
}

/// <summary>
/// protectedNode setter
/// The ExecutableNode protected by the ExceptionHandler. If an exception propagates
/// out of the protectedNode and has a type matching one of the exceptionTypes, then
/// it is caught by this ExceptionHandler.
/// </summary>
void ExceptionHandler::setProtectedNode(shared_ptr<ExecutableNode> value) {
    protectedNode_ = value;
}

} // namespace uml
